package com.zxl.jdk8test;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * java.util.Stream 表示能应用在一组元素上一次执行的操作序列。
 * Stream 操作分为中间操作或者最终操作两种，最终操作返回一特定类型的计算结果，而中间操作返回Stream本身，
 * 这样你就可以将多个操作依次串起来。Stream 的创建需要指定一个数据源，比如 java.util.Collection(此接口提供了stream()方法)的子类，
 * List或者Set， Map不支持。Stream的操作可以串行执行或者并行执行。
 * @author zxl
 *
 */
public class StreamTest {
    
    public static void main(String[] args) {
        List<String> list = TestUtil.getStringList();
//        filterTest(list);
//        sortedTest(list);
//        mapTest(list);
//        matchTest(list);
//        countTest(list);
//        reduceTest(list);
//        parallelTest(list);
          limitTest(list,3L);
//        List<Person> persons = TestUtil.getPersonList();
//        System.out.println("==============原始的集合===============");
//        for (Person p : persons) {
//            System.out.println(p);
//        }
//        Random rd = new Random();
//        persons.forEach(p -> { p.setGender(rd.nextInt(3) == 0 ? "男" : "女");});
//        System.out.println("==============foEach之后的集合===============");
//        for (Person p : persons) {
//            System.out.println(p);
//        }
    }
    
    /**
     * 过滤通过一个predicate接口来过滤并只保留符合条件的元素，该操作属于中间操作，
     * 所以我们可以在过滤后的结果来应用其他Stream操作（比如forEach）。
     * forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作，
     * 所以我们不能在forEach之后来执行其他Stream操作。 不影响原集合
     *
     */
    public static void filterTest(List<String> list){
        //过滤以a开头的元素，将过滤的元素循环输出。
        list.stream().filter((str) -> str.startsWith("a")).forEach((str) -> System.out.println(str));;
    }
    
    /**
     * 排序 不影响原集合
     * @param list
     */
    public static void sortedTest(List<String> list){
        //过滤以a开头的元素，将过滤的元素循环输出。不影响原集合
        list.stream().sorted().forEach((str) -> System.out.println(str));;
        System.out.println("==============以下为自定义排序===排序规则乱写的，无视===============");
        list.stream().sorted((s1,s2) -> {
                if (s1.startsWith("c")) return -1;
                else if (s1.startsWith("b")) return 0;
                else return 1;
            }).forEach((str) -> System.out.println(str));;
            
    }
    
    /**
     * 中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象，
     * map返回的Stream类型是根据你map传递进去的函数的返回值决定的 
     * 不影响原集合
     * @param list
     */
    public static void mapTest(List<String> list){
        //调用person的构造方法。每次传入的是一个list集合中的一个元素，
        //此时将调用person的一个String参数的构造方法。然后最终返回一个person的list集合
        list.stream().map(Person::new).forEach(System.out::println);
        System.out.println("--------------");
        //效果一样
        list.stream().map(Person::new).collect(Collectors.toList()).forEach(System.out::println);
    }
    
    /**
     * Stream提供了多种匹配操作，允许检测指定的Predicate是否匹配整个Stream。
     * 所有的匹配操作都是最终操作，并返回一个boolean类型的值
     * @param list
     */
    public static void matchTest(List<String> list){
        //匹配到任意一个
        System.out.println(list.stream().anyMatch((s) -> s.startsWith("a")));//true
        //全部匹配
        System.out.println(list.stream().allMatch((s) -> s.startsWith("a")));//false
        //全不匹配
        System.out.println(list.stream().noneMatch((s) -> s.startsWith("a")));//false
    }
    
    /**
     * 计数是一个最终操作，返回Stream中元素的个数，返回值类型是long。
     * @param list
     */
    public static void countTest(List<String> list){
        //总个数
        System.out.println(list.stream().count());//true
        //符号条件的个数
        System.out.println(list.stream().filter((s) -> s.startsWith("a")).count());
    }
    
    /**
     * 这是一个最终操作，允许通过指定的函数来讲stream中的多个元素规约为一个元素，
     * 规约后的结果是通过Optional接口表示的
     * @param list
     */
    public static void reduceTest(List<String> list){
        //总个数
        Optional<String> optional = list.stream().reduce((s1,s2) -> s1 + "___" + s2);//true
        optional.ifPresent(System.out::println);
    }
    
    /**
     * 串行Stream上的操作是在一个线程中依次完成，而并行Stream则是在多个线程上同时执行
     * 唯一需要做的改动就是将stream()改为parallelStream()。
     * @param list
     */
    public static void parallelTest(List<String> list){
        //串行
        long t0 = System.nanoTime();
        long count = list.stream().sorted().count();
        System.out.println(count);
        long t1 = System.nanoTime();
        long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
        System.out.println(millis);
        //并行 效率快
        t0 = System.nanoTime();
        count = list.parallelStream().sorted().count();
        System.out.println(count);
        t1 = System.nanoTime();
        millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
        System.out.println(millis);
    }
    
    /**
     * 返回一个流的元素组成的流,截断长度不超过最大容量。
     * @param list
     * @param maxSize 最大容量
     */
    public static void limitTest(List<String> list,Long maxSize){
        list.stream().limit(maxSize).collect(Collectors.toList()).forEach(System.out::println);
    }
    
}
